using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using TagTool.Devices;
using TagTool.Devices.DataStructures;
using System.Drawing;
using TagTool.GraphicTypes;

namespace TagTool.Devices.Tablet
{
    /// <summary> Represents a digital tablet input device for windows </summary>
    /// <remarks>
    /// Communication with tablet devices is done via wintab32.dll.
    /// Devices currently known to work:
    /// Summagraphics: Summasketch 1/2, Wacom: Intuos 2
    /// </remarks>
    public sealed class WinTablet : ITabletDevice
    {
        #region Members
		
        /// <summary> A contextHandle to a manager context </summary>
        /// <remarks> Can be used to configure certain device options </remarks>
        private IntPtr manager = IntPtr.Zero;
        /// <summary> The default logical context </summary>
        private WinTabletContext defaultContext;
        /// <summary> Generic list of contexts </summary>
        private IList<ITabletContext> contextList;

        /// <summary> The device name </summary>
        private string name;
        /// <summary> The device id </summary>
        private uint deviceId;

        /// <summary> Switch for trace level </summary>
        private static TraceSwitch tabletSwitch;
        /// <summary> Writer for trace information </summary>
        private static TextWriter tabletWriter;
        /// <summary> Listener for tracing </summary>
        private static TextWriterTraceListener tabletListener;

 		#endregion

        /// <summary> Standard constructor. Initializes tracing and the window </summary>
        public WinTablet(uint deviceId)
        {
            this.deviceId = deviceId;
            defaultContext = new WinTabletContext(deviceId);
            contextList = new List<ITabletContext>();

            // TRACING
            tabletSwitch = new TraceSwitch("tabletSwitch", "Switch tablet tracing");
            if (tabletSwitch.Level != TraceLevel.Off)
            {
                tabletWriter = File.CreateText(@"WinTablet.log");
                if (tabletWriter != null)
                {
                    tabletListener = new TextWriterTraceListener(tabletWriter, "tabletListener");
                    Trace.Listeners.Add(tabletListener);
                }
            }
        }

        /// <summary> Destructor. Makes sure to close the tablet </summary>
        ~WinTablet()
        {
            Disconnect();
        }

        #region Properties

        /// <summary> Property Name </summary>
        public string Name
        {
            get
            {
                if (string.IsNullOrEmpty(name))
                {
                    WTContext context = new WTContext();
                    WTFunction.WTInfo((uint)WTInfoCategory.Devices, (uint)WTIDevices.Name, ref context);
                    name = context.Name;
                }
                return name;
            }
            set
            {
                name = value;
            }
        }

        /// <summary> Property DeviceId </summary>
        public int DeviceId
        {
            get
            {
                return (int)deviceId;
            }
        }

        /// <summary> Property DefaultContext </summary>
        public ITabletContext DefaultContext
        {
            get
            {
                return defaultContext;
            }
        }

        /// <summary> Property Contexts </summary>
        public IList<ITabletContext> Contexts
        {
            get
            {
                return contextList;
            }
        }

        /// <summary> Property X </summary>
        public double X
        {
        	get { return defaultContext.Location.X; }
        }

        /// <summary> Property Y </summary>
        public double Y
        {
            get { return defaultContext.Location.Y; }
        }

        /// <summary> Property Z </summary>
        public double Z
        {
            get { return defaultContext.Location.Z; }
        }

        /// <summary> Property Orientation </summary>
        public TagTool.Devices.DataStructures.Orientation Orientation
        {
            get { return defaultContext.Orientation; }
        }

        /// <summary> Property Location </summary>
        public PointD Location
		{
            get { return defaultContext.Location; }
		}

        /// <summary> Property NormalPressure </summary>
        public uint NormalPressure
        {
            get { return defaultContext.NormalPressure; }
        }

        /// <summary> Property TangentPressure </summary>
        public uint TangentPressure
        {
            get { return defaultContext.TangentPressure; }
        }

        /// <summary> Property Buttons </summary>
        public uint Buttons
        {
            get { return defaultContext.Buttons; }
        }

        /// <summary> Property Resolution </summary>
        public DeviceResolution Resolution
		{
            get { return defaultContext.Resolution; }
		}

        /// <summary> Property OrientationResolution </summary>
        public DeviceResolution OrientationResolution
		{
            get { return defaultContext.OrientationResolution; }
		}

        /// <summary> Property IsInContextProximity </summary>
        public bool IsInContextProximity
        {
            get { return defaultContext.IsInContextProximity; }
        }

        /// <summary> Property IsInHardwareProximity </summary>
        public bool IsInHardwareProximity
        {
            get { return defaultContext.IsInHardwareProximity; }
        }
 
        /// <summary> Property Available </summary>
        public bool Available
        {
            get
            {
                return defaultContext.Available;
            }
        }       

        /// <summary> Property Enabled </summary>
        /// <remarks>
        /// Calls WTGet() and inpects the status of the context,
        /// which is zero if the device is disabled.
        /// </remarks>
        public bool Enabled
        {
            get
            {
                return defaultContext.Enabled;
            }
        }

        /// <summary> Property DefaultContextHandle </summary>
        public IntPtr DefaultContextHandle
        {
            get
            {
                return defaultContext.ContextHandle;
            }
        }
        
        #endregion


        #region Methods

        /// <summary> Opens default context to a tablet device </summary>
        public void Connect()
        {
            defaultContext.Connect();
        }

        /// <summary> Closes the default context and sets the contextHandle to it to zero </summary>
        public void Disconnect()
        {
            defaultContext.Disconnect();
        }

        /// <summary> Closes all but the default context </summary>
        public void CloseContexts()
        {
            foreach (WinTabletContext context in contextList)
            {
                context.Disconnect();
            }
        }

        /// <summary> Enables the device </summary>
        /// <returns> True if device was successfully enabled </returns>
        public bool Enable()
        {
            return defaultContext.Enable();
        }

        /// <summary> Disables the device </summary>
        /// <returns> True if device was successfully disabled </returns>
        public bool Disable()
        {
            return defaultContext.Disable();
        }

        /// <summary> Get the resolution of a device </summary>
        /// <param name="deviceId"> The device id </param>
        /// <returns> The device's resolution </returns>
        private DeviceResolution GetResolution(uint deviceId)
        {
            return defaultContext.Resolution;
        }

        private void GetDeviceMargins(ref int dvc_xmargin, ref int dvc_ymargin, ref int dvc_zmargin)
        {
            uint category = (uint)WTInfoCategory.Devices + deviceId;

            WTFunction.WTInfoInt(category, (uint)WTIDevices.XMargin, ref dvc_xmargin);
            WTFunction.WTInfoInt(category, (uint)WTIDevices.YMargin, ref dvc_ymargin);
            WTFunction.WTInfoInt(category, (uint)WTIDevices.ZMargin, ref dvc_zmargin);
        }

        /// <summary> Creates a "menu" of contexts on the tablet </summary>
        /// <param name="side"> 0 = left, 1 = right, 2 = top, 3 = bottom </param>
        /// <param name="width"> Requested width in millimeters </param>
        /// <param name="rows"> Number of rows </param>
        /// <param name="columns"> Number of columns </param>
        /// <param name="padding"> Padding between contexts in millimeters </param>
        public void CreatePaperMenu(int side, int width, int rows, int columns, int padding)
        {
            //int biasX = 200;
            //int biasY = 200;
            //int factor = 100;
            //int x = defaultContext.Resolution.X.Maximum;
            //int y = defaultContext.Resolution.Y.Maximum;
            //WTContext context;
            //IntPtr handle;
            //int menuPadding = factor * padding;

            //int menuWidth = factor * width * columns;
            //int menuItemWidth = menuWidth - 2 * menuPadding;
            //int menuItemHeight = (y - menuPadding * (rows + 1)) / rows;

            //for (int i = 0; i < columns; i++)
            //{
            //    int xOffset = menuPadding * i + menuPadding;

            //    for (int j = 0; j < rows; j++)
            //    {
            //        int yOffset = j * (menuPadding + menuItemHeight) + menuPadding;
            //        context = GetDefaultContext();
            //        context.InOrgX = (uint)(xOffset - biasX);
            //        context.InOrgY = (uint)(yOffset - biasY);
            //        context.InExtX = (uint)menuItemWidth;
            //        context.InExtY = (uint)menuItemHeight;
            //        context.OutOrgX = 0;
            //        context.OutOrgY = 0;
            //        context.OutExtX = context.InExtX;
            //        context.OutExtY = context.InExtY;

            //        IntPtr contextHandle = WTFunction.WTOpen(windowHandle, ref context, true);
            //        if (contextHandle != IntPtr.Zero)
            //        {
            //            contextList.Add(contextHandle);
            //        }
            //    }
            //}
            //context = GetDefaultContext();
            //context.InOrgX = (uint)(menuWidth + 1);
            //context.InOrgY = 0;
            //context.InExtX = (uint)(x - menuWidth - 1);
            //context.InExtY = (uint)y - 1;
            //context.OutOrgX = 0;
            //context.OutOrgY = 0;
            //context.OutExtX = context.InExtX;
            //context.OutExtY = context.InExtY;

            //handle = WTFunction.WTOpen(windowHandle, ref context, true);
            //if (handle != IntPtr.Zero)
            //{
            //    contextList.Add(handle);
            //}
        }

        public void SplitContext(int percent)
        {
            //WTContext leftContext = GetDefaultContext();
            //WTContext rightContext = GetDefaultContext();

            //uint x = (uint)(leftContext.InExtX / 100.0 * percent);
            //leftContext.InExtX = x;
            //rightContext.InOrgX = x + 1;

            //IntPtr leftHandle = WTFunction.WTOpen(windowHandle, ref leftContext, true);
            //IntPtr rightHandle = WTFunction.WTOpen(windowHandle, ref rightContext, true);

            //contextList.Add(leftHandle);
            //contextList.Add(rightHandle);
        }

        private void WriteTrace(string function, string context)
        {
        }

        #endregion
    }
}
